package zsl.algo;
import java.io.IOException;
import java.util.Vector;

import zsl.generator.DefaultWordListGenerator;
import zsl.generator.UniformWordListGenerator;
import zsl.generator.WordListGenerator;
import zsl.utils.MergeTimeInfo;
import zsl.utils.WordCount;
import zsl.utils.WordCountList;

public class MergeAlgo {
	public static Vector<WordCountList> merge(Vector<WordCountList> lists,
			int mergeNum, MergeTimeInfo mInfo) {
		int numOfMergedList = (int)Math.ceil(lists.size() / (double)mergeNum) ;
		Vector<WordCountList> mergedList = new Vector<>(numOfMergedList, 5);
		if (mInfo != null) {
			for (int i = 0; i < numOfMergedList; i++) {
//				long start = System.currentTimeMillis();
				mergedList.add(mergePart(i*mergeNum, mergeNum, lists, mInfo));
//				long end = System.currentTimeMillis();
//				System.out.println("mergePart "+i + " "+(end-start)/4);
			}
		}else {
			for (int i = 0; i < numOfMergedList; i++) {
				mergedList.add(mergePart(i*mergeNum, mergeNum, lists));
			}
		}
		
		return mergedList;
	}
	
	private static WordCountList mergePart(int start, int mergeNum, Vector<WordCountList> lists){
		int end = Math.min(start + mergeNum, lists.size());
		WordCountList list0 = lists.get(0);
		int listDepth = list0.size();
		WordCount wc;
		int count = 0;
		
		WordCountList mergedList = new WordCountList(listDepth);

		for (int i = 0; i < listDepth; i++) {
			wc = list0.get(i);
			String word = wc.getWord();
			count = 0;
			for (int j2 = start; j2 < end; j2++) {
				count += lists.get(j2).getCount(word);
			}
			mergedList.add(new WordCount(word, count)); //add without order, sort by calling descOrder()
		}
		mergedList.descOrder();

		return mergedList;
	}
	
//	private static WordCountList mergePart(int start, int mergeNum, Vector<WordCountList> lists){
//		int end = Math.min(start + mergeNum, lists.size());
//		WordCountList list0 = lists.get(0);
//		int listDepth = list0.size();
//		WordCount wc;
//		int count = 0;
//		
//		WordCountList mergedList = new WordCountList(listDepth);
//		
//		WordCountList listStart = lists.get(start);
//		
//		for (int i = 0; i < listDepth; i++) {
//			wc = listStart.get(i);
//			String word = wc.getWord();
//			count = wc.getCount();
//			for (int j2 = start+1; j2 < end; j2++) {
//				count += lists.get(j2).getCount(word);
//			}
//			wc.setCount(count);  //no need to create new objects
//		}
//		
//		mergedList.descOrder();
//		
//		return listStart;
//	}
	
	private static WordCountList mergePart(int start, int mergeNum, Vector<WordCountList> lists, MergeTimeInfo mInfo){
		int end = Math.min(start + mergeNum, lists.size());
		WordCountList list0 = lists.get(0);
		int listDepth = list0.size();
		WordCount wc;
		int count = 0;
		
		WordCountList listStart = lists.get(start).clone();
		
		long startTime, endTime, addedStart, addedEnd, addedTotal=0, total=0;
		
		for (int i = 0; i < listDepth; i++) {
			startTime = System.nanoTime();
			wc = listStart.get(i);
			String word = wc.getWord();
			count = wc.getCount();
			endTime = System.nanoTime();
			total += endTime - startTime;
			
			
			for (int j2 = start+1; j2 < end; j2++) {
				lists.get(j2).getCount(word);
				addedStart = System.nanoTime();
				count += lists.get(j2).getCount(word);
				addedEnd = System.nanoTime();
				addedTotal += addedEnd-addedStart;
			}
			
			
			wc.setCount(count);
//			mergedList.add(new WordCount(word, count)); //add without order, sort by calling descOrder()
		}
		
		mInfo.setMergeTime(mInfo.getMergeTime()+total);
		mInfo.setAddedMergeTime(mInfo.getAddedMergeTime()+addedTotal);
		
		startTime = System.nanoTime();
		listStart.descOrder();
		endTime = System.nanoTime();
		mInfo.setAddedSortTime(mInfo.getAddedSortTime() + endTime - startTime);

		return listStart;
	}
	
	public static void main(String[] args) throws IOException {
		int dictLen = 100000;
		int numOfWords = 100;
		long seed = 1000L;
		int numOfLists = 200;
		WordListGenerator wg = new UniformWordListGenerator(dictLen, seed);
		
		//generate lists of words
		Vector<WordCountList> lists = new Vector<>();
		
		for (int j = 0; j < numOfLists; j++) {
			lists.add(wg.generateWords(numOfWords));
		}
		System.out.println("in Run: finish generator");
		double sum = 0;
		long start = 0, end = 0;
		for (int i = 0; i < 10; i++) {
			start = System.currentTimeMillis();
			Vector<WordCountList> mergedList = merge(lists, 100, null);
			end = System.currentTimeMillis();
			sum += (end - start);
		}
		
		System.out.println("average merge time is " + sum / 10);
		
	}
}
